package service

import (
	"buding-ai/internal/core"
	"buding-ai/internal/repository"
	"buding-ai/internal/repository/model"
	"buding-ai/internal/web/dto"
	"buding-ai/internal/web/response"
	"buding-ai/pkg/utils/jwt"
	"buding-ai/pkg/utils/password"
	"errors"
	"sync"
)

var (
	ErrUserNotFound       = errors.New("user not found")
	ErrInvalidCredentials = errors.New("invalid username or password")
	ErrUserDisabled       = errors.New("user account is disabled")
	ErrDatabase           = errors.New("a database error occurred")
)

type AuthService struct {
	userRepository *repository.UserRepository
}

var (
	authSrv  *AuthService
	authOnce sync.Once
)

func NewAuthService() *AuthService {
	authOnce.Do(func() {
		authSrv = &AuthService{
			userRepository: repository.GeUserRepository(),
		}
	})
	return authSrv
}

func (srv *AuthService) Login(loginDTO dto.LoginDTO) (*response.LoginVO, error) {
	// 查询用户
	user, err := srv.userRepository.GetByUserName(loginDTO.Username)
	if err != nil {
		return nil, err
	}

	// 验证密码
	if !password.CheckPassword(loginDTO.Password, user.Salt, user.Password) {
		return nil, ErrInvalidCredentials
	}
	// 检查用户状态
	if user.Status != 1 {
		return nil, ErrUserDisabled
	}

	token, err := jwt.GenerateToken(user)
	if err != nil {
		return nil, errors.New("token 生成失败:" + err.Error())
	}

	//更新最后登陆时间
	srv.userRepository.UpdateLoginTime(user.ID)

	return &response.LoginVO{
		Token: token,
		User:  response.ToUserVO(*user),
	}, nil
}

func (srv *AuthService) GetOne(UserID uint) (*response.UserVO, error) {
	// 查询用户信息
	user, err := srv.userRepository.GetById(UserID)
	if err != nil {
		return nil, err
	}
	vo := response.ToUserVO(*user)
	return &vo, nil
}

func (srv *AuthService) RestPassword(resetDTO dto.PasswordResetDTO) error {
	// 查询用户
	var user model.User
	if err := core.DB.Where("username = ?", resetDTO.Username).First(&user).Error; err != nil {
		return errors.New("用户不存在")
	}
	// 验证旧密码
	if !password.CheckPassword(resetDTO.OldPassword, user.Salt, user.Password) {
		return errors.New("旧密码错误")
	}

	// 生成新密码和盐值
	encodedPassword, salt := password.GeneratePassword(resetDTO.NewPassword)

	// 更新密码和盐值
	updates := map[string]interface{}{
		"password": encodedPassword,
		"salt":     salt,
	}

	if err := core.DB.Model(&user).Updates(updates).Error; err != nil {
		return errors.New("更新密码失败:" + err.Error())
	}
	return nil
}
